<?php

namespace app\common\library;

use app\admin\library\Auth;
use Exception;
use think\Db;
use think\exception\PDOException;
use think\exception\ValidateException;
use app\admin\model\park\Hub;
use app\admin\model\park\Order;
use app\admin\model\park\ParkingPlace;
use app\admin\model\park\Region;
use app\admin\model\park\Rule;
use Swoole\Client;

/**
 * 停车服务类
 */
class ParkService
{
    /*
    * 打开地桩
    */
    public static function Open($id){
        $parkingPlace = ParkingPlace::where('id', $id)->find();
        if(!$parkingPlace) {
            throw new Exception('id 不正确');
        }
        if(class_exists('Client')){
            $client = new Client(SWOOLE_SOCK_TCP);
            $client->set(array(
                'open_eof_check' => true,
                'package_eof' => "\r\n",
            ));
            if (!$client->connect('127.0.0.1', 9998, -1)) {
                exit("connect failed. Error: {$client->errCode}\n");
            }
            $client->send("open $id\r\n");
            $result = $client->recv();
            $client->close();
        }
        return $result;
    }

    // 关闭地桩
    public static function Close($id){
        $parkingPlace = ParkingPlace::where('id', $id)->find();
        if(!$parkingPlace) {
            throw new Exception('id 不正确');
        }
        if(class_exists('Client')){
            $client = new Client(SWOOLE_SOCK_TCP);
            $client->set(array(
                'open_eof_check' => true,
                'package_eof' => "\r\n",
            ));
            if (!$client->connect('127.0.0.1', 9998, -1)) {
                exit("connect failed. Error: {$client->errCode}\n");
            }
            $client->send("close $id\r\n");
            $result = $client->recv();
            $client->close();
        }
    }

    // 开锁并生成订单，开始计费
    public static function CreateOrder($id, $userId) {
        $parkingPlace = ParkingPlace::where('id', $id)->find();
        $hub = Hub::where('id', $parkingPlace['hub_id'])->find();
        if(!$parkingPlace) {
            throw new Exception('id 不正确');
        }
        if($parkingPlace['online_status'] != 'online') {
            throw new Exception('设备不在线，不能停车，请稍后再试');
        }
        if($hub['online_status'] != 'online') {
            throw new Exception('设备不在线，不能停车，请稍后再试');
        }
        if($parkingPlace['status'] != 'idle') {
            throw new Exception('此停车位不是空闲状态，不能再停车');
        }

        $rules = Db::name('rule')->where('region_id', $parkingPlace['region_id'])
                ->order('start')
                ->field('name,start,end,type,unit,amount')
                ->select();
        $rules = collection($rules)->toArray();
        $order = new Order;
        $order->user_id = $userId;
        $order->parking_place_id = $id;
        $order->region_id = $parkingPlace['region_id'];
        $order->rule_json = json_encode($rules);
        $order->starttime = date('Y-m-d H:i:s');
        $order->amount = 0;
        $order->save();

        $parkingPlace->status = 'charging';
        $parkingPlace->start_charge_time = time();
        $parkingPlace->save();

        // TODO 合上地桩 然后等车进来再打开地桩
        self::Close($id);
        return $order;
    }

     // 准备结束订单，计算费用以便支付
    public static function PreLeave($id){ 
        $fee = self::CalcFee($id);
        $order = Order::where('parking_place_id', $id)
                ->where('pay_status', 'pendding')
                ->order('id', 'desc')
                ->find();
        $order->amount = $fee['amount'];
        $order->rule_json = json_encode($fee['rules']);
        $order->fee_detail_json = json_encode($fee['details']);
        $order->endtime = date('Y-m-d H:i:s');
        $order->save();
        return $order;
    }

    // 结束订单，开锁让车离开
    public static function Leave($orderId){ 
        $order = Order::where('id', $orderId)->find();
        $order->pay_status = 'paid';
        $order->save();
        $parkingPlace = ParkingPlace::where('id', $order->parking_place_id)->find();
        // 
        $parkingPlace->status = 'wait';
        $parkingPlace->end_charge_time = time();
        $parkingPlace->save();
        self::Close($order->parking_place_id);
    }

    // 计费费用
    public static function CalcFee($id) {
        $parkingPlace = ParkingPlace::where('id', $id)->find();
        if(!$parkingPlace) {
            throw new Exception('id 不正确');
        }
        if($parkingPlace['online_status'] != 'online') {
            throw new Exception('设备不在线，不能停车，请稍后再试');
        }
        if($parkingPlace['status'] != 'charging') {
            throw new Exception('此停车位是空闲状态，不能计费');
        }

        $rules = Db::name('rule')->where('region_id', $parkingPlace['region_id'])
                ->order('start')
                ->field('name,start,end,type,unit,amount')
                ->select();
        $rules = collection($rules)->toArray();
        $order = Order::where('parking_place_id', $id)
                ->where('pay_status', 'pendding')
                ->order('id', 'desc')
                ->find();
        $mins = floor((time() - strtotime($order['starttime'])) / 60);
        $amount = 0;
        $details = [];
        for ($i=0; $i < count($rules); $i++) { 
            $rule = $rules[$i];
            if($rule['type'] == 'lt_start') {
                $segment = $mins;
                if($mins > $rule['start']) {
                    $segment = $rule['start'];
                }
                $tmp = number_format(ceil($segment / $rule['unit']) * $rule['amount'], 2);
                $details[] = ['name'=> $rule['name'], 'amount'=> $tmp];
                $amount += $tmp;
            } else if($rule['type'] == 'between') {
                $segment = 0;
                if($mins < $rule['start'])
                    continue;
                if($mins >= $rule['end']) {
                    $segment = $rule['end'] - $rule['start'];
                } else {
                    $segment = $mins - $rule['start'];
                }
                $tmp = number_format(ceil($segment / $rule['unit']) * $rule['amount'], 2);
                $details[] = ['name'=> $rule['name'], 'amount'=> $tmp];
                $amount += $tmp;
            }  else if($rule['type'] == 'gt_start') {
                $segment = 0;
                if($mins < $rule['start'])
                    continue;
                $segment = $mins - $rule['start'];
                $tmp = number_format(ceil($segment / $rule['unit']) * $rule['amount'], 2);
                $details[] = ['name'=> $rule['name'], 'amount'=> $tmp];
                $amount += $tmp;
            } 
        }
        $amount = number_format($amount, 2);
        return [
            'mins' => $mins,
            'amount' => $amount,
            'details' => $details,
            'rules' => $rules
        ];
    }
}
